;;; -*- Mode: LISP; Syntax: Common-lisp; Package: USER; Base: 10 -*-
;;; Name: Rylan Kwock, Tony Gaskel, Dave Morse, Kurt Teichman 
;;; Date: 4-25-2011
;;; Course: ICS313        Assignment:   7
;;; File: game.lisp
;;;
;;; Code inspired by author: Conrad Barski (www.lisperati.com - Casting SPELs)


;;; Uncomment the following line if your system requries it.
;;;  (defparameter tpl:*print-length* nil)


;;;  PATH ISSUES - note that the default PATH settings are for
;;;       UH-Unix Public-HTML folder contents. 
;;;
;;;  Example start-up:  (load "~/public_html/game.lisp")
;;;
;;;  To Change program PATH settings for Your environment,
;;;       edit the "~/public_html/" string in *path-to-game* parameter:


(defparameter *path-to-game* '"~/public_html/")    ;; edit this for your PATH


(defparameter *map* '(         ;; defines the "rooms" and their attributes
;;--------- Ground level rooms -------
  (lobby
   (You are in the lobby of the mansion. The sound of clawing sets your nerves on end. It is probably best to not go back outside right now...)
   (west door outside)
   (north door gun-room)
   (south door study)
   (east hall hallway)
  )
  (hallway
   (A long hallway with several side tables and giant mirrors lining the path. The tacky floral wallpaper is beginning to peel off of the walls reminding you of a decrepit 1920s hotel.)
   (west hall lobby)
   (east hall stairway)
   (south door bathroom)
  )
  (study
   (A flask of thick brown liquid rests on the top of a bookshelf. Oddly there are no chairs in the room.)
   (north door lobby)
  )
  (stairway
   (A creaky wooden stairwell appears to lead into a dimly lit basement. The splintered railings are in desperate need of paint.)
   (west hall hallway)
   (north door dining-room)
   (east door library)
   (south door bedroom)
   (downstairs stairway passage)
  )
  (bathroom (Spots of black mold dot the grout between the bathroom tiles.  The acrid smell of bathroom cleaner saturates the air.  The seashell-pink walls are also not to your liking.)
   (north door hallway)
   (east door bedroom)
  )
  (bedroom
   (A large palanquin-style bed rests at the far end of the room. The room is filled with a faded citrus scent wafting from the hardwood floor.)
   (north door stairway)
   (west door bathroom)
  )
  (dining-room (A long dining table sits in the middle of the room.  The shiny oak surface is lit by what appears to be a large glass chandelier.  The table is set for two.)
   (east door kitchen)
   (south door stairway)
  )
  (kitchen
   (A white-tiled kitchen shines in the white light. The stovetop is rusted over with several dead bugs littering the range.)
   (west door dining-room)
  )
  (library
   (Every wall of the room is covered with old weathered books. The back wall of the room is filled with stacked chairs for some reason. None of them appear to be comfortable.)
   (west door stairway)
  )
  (gun-room
   (Glittering trophies line the walls while the mounted heads of several game animals stare down at you. A large armchair faces a portrait of a young gypsy woman. Two gun racks are set under the portrait but only one gun remains.)
   (south door lobby)
  )
;;-------- Basement rooms -------
  (passage
   (Your footsteps echo on the solid concrete floor. Bare plaster walls lead to a nondescript brick wall.)
   (upstairs stairway stairway)
   (east door stock-room)
   (west door cellar)
  )
  (stock-room
   (Linoleum tiling covers the floor and the dank smell of mildew hangs in the air. A rack of wine sits in the corner caked with dust. A bottle of 1967 Chateau peeks out at you.)
   (west door passage)
  )
  (cellar
   (A solitary lightbulb hangs in the center of the room and casts awkward shadows over the tattered carpet. Books are stacked neatly on the table and surrounded by a sea of wrinkled papers.  One of these papers seems to have a puzzle written on it.)
   (east door passage)
   (south door closet)
   (west door laboratory)
  )
  (closet
   (A simple closet that is mostly empty except for several shoeboxes on the top shelf. A warm breeze wafts from above. Several cobwebs are tossed about on the ceiling. The room is unlit except from the light entering from the entrance you are standing in.  Puzzling scribbles mark the back wall.)
   (north door cellar)
   (south door secret-room)
  )
  (laboratory
   (A plastic-covered armchair faces a dusty ficus. A tattered and worn reflection stares back at you from a blank television screen. Your haggard reflection reminds you of the killer bear awaiting you outside.)
   (east door cellar)
   (south door laundry)
  )
  (laundry
   (Bright flourescent lighting illuminates the tacky wallpaper along the hallway. The cheaply tiled flooring is marred by scuffs and scratches.)
   (north door laboratory)
   (south door control-room)
  )
  (control-room
   (A worn office chair faces an old computer. The computer monitor casts a dull green glow over the room. Half a floppy disk sticks out from the disk drive. A puzzle flickers on the computer screen.)
   (north door laundry)
  )
  (secret-room
   (Three long tables stretch across the room and are covered in old dot-matrix printouts. A comfortable looking office chair sits forlorn in a corner. The floor is chipped and riddled with cracks.  A puzzle is laid out across the center table.)
   (north door closet)
   (east door gypsy-room)
  )
  (gypsy-room
   (A withered old woman sits in a rocking chair and stares intently at you. A shotgun rests across her lap as she drums her fingers on the stock. A bearskin hangs on the wall and the room is by candles of bear fat.)
   (west door secret-room)
  )
;;----------- Ready... FIGHT! -----
  (outside
   (There is a crazed bear waiting to tear you apart and feast on your entrails.)
  )
 )
)



(defparameter *objects* '(      ;; defines the "objects" and their attributes.
  (diary
   "October 29th 1997. Madeline got into the guns again and shot Roberto in the arm.
November 1st 1997. Roberto is recovering slowly. The doctor has prescribed two months bed rest and cod oil.
November 2nd 1997. Locked the guns in the gun room above the mantleplace. Hid the key in the basement. Madeline hates the basement."
   1 ;; Associated point value
  )
  (pen
   "A sturdy looking fountain pen. The nib appears bent as though it has been shoved into a tight space.
   The sharp tip looks like it could put an eye out."
   2 ;; Associated point value
  )
  (matchbox
   "A tiny box filled with old matches. Brown dust covers most of the match heads."
   1 ;; Associated point value
  )
  (knife
   "The steel of the knife glints in the light. The black wooden handle fits snugly in your hand."
   12 ;; Associated point value
  )
  (frozen-fish
   "The frozen herring stares at you blankly. You recall something about the predilection of bears for herring.
   You also seem to recall a herring being used to chop down a tree once. A delicious and possibly potent weapon."
   1 ;; Associated point value
  )
  (gun
   "A tacky red film covers the tip of the rifle and brownish splotches on the stock. It appears as though the rifle has not been cleaned in several years."
   65 ;; Associated point value
  )
  (wine-bottle
   "A vintage bottle of 1967 Chateau wine. A scribble at the bottom of the label indicates something about 180 proof liquid inside."
   1 ;; Associated point value
  )
  (silver-key
   "A generic looking key. You recall seeing a silver lock somewhere in this house."
   1 ;; Associated point value
  )
  (rusty-key
   "A flimsy brown key. The key appears to be the same kind used to lock bicycles and flimsy doors."
   1 ;; Associated point value
  )
  (morse-code-cipher
   "A wrinkled sheet of paper covered in random dots and dashes. The paper smells of stale chips and is smudged with orange powder."
   1 ;; Associated point value
  )
  (ceasar-cipher
   "The crumpled shred of paper smells of old shoes. The following text is scribbled across the page: JU XJMM CF B SBJOZ EBZ."
   1 ;; Associated point value
  )
  (heavy-key
   "The key is etched with the following inscription: Madeline DO NOT TOUCH."
   1 ;; Associated point value
  )
  (golden-key
   "A golden skull adorns this odd key.  There is no doubt that this key does not unlock a normal door."
   1 ;; Associated point value
  )
  (doll
   "A tattered doll that is missing an arm.  The name: Roberto is stitched on his back."
   5 ;; Associated point value
  )
 )
)


(defparameter *object-locations* '(
  (diary study)
  (pen study)
  (gun gun-room)
  (knife kitchen)
  (frozen-fish kitchen)
  (matchbox library)
  (wine-bottle stock-room)
  (doll gypsy-room)
 )
)


(defparameter *puzzle-locations* '(
  (cellar secret-puzzle-a)
  (closet secret-puzzle-b)
  (control-room secret-puzzle-c)
  (secret-room master-puzzle)
 )
)

(defparameter *key-rooms* '(    ;; relates a key to its door-lock
    (rusty-key closet)
    (silver-key laboratory)
    (heavy-key gun-room)
    (golden-key secret-room)
  )
)

 ;; Defines the puzzle items, similar format to the game rooms
 ;; PUZZLE FORMAT: ((question) (required-items) (answer) (answer-response) (item))
(defparameter *puzzles* '(
 (secret-puzzle-a     ;; puzzle located in root-cellar
   "Someone has built a house where every side of the house is facing south. Suddenly, a bear walks by, trapping the person in their own home! What color is the bear?~%"
   NIL         ;; no items required to solve puzzle
   ("white")
   "The paper appears to be torn from the book, \"Polar-Peccadilloes\". As you open the book, two keys fall out from between the pages."
   (rusty-key silver-key))
 (secret-puzzle-b     ;; puzzle located in closet
   "In the sentence: \"I'll be eleven next month.\" one can find a \"bee\"! The word \"fish\" can be found in the sentence: \"Tell me if I should start now.\" What animal can be found in the following sentence: \"It will be a rainy day.\"?~%"
   (morse-code-cipher) ;; morse code cipher required to translate puzzle
   ("bear")
   "You notice that the sentence: \"JU XJMM CF B SBJOZ EBZ.\" is scribbled at the bottom of the page. Suddenly, you realize that you are looking at a Ceasar cipher, shifted by a single letter!"
   (ceasar-cipher golden-key))
 (secret-puzzle-c     ;; puzzle located in control-room
   "You have been condemned to death. You must choose to be placed in one of three rooms. The first room is full of fire, the second room is full of assassins with loaded guns, and the third room is full of bears that have not eaten in three years. Which number room is the safest?~%"
   NIL         ;; no items required to solve puzzle
   ("3")
   "In frustration at the solutions to these ridiculous riddles, you kick over an empty shoebox. A torn sheet of paper falls out of the box."
   (morse-code-cipher))
 (master-puzzle      ;; puzzle located in secret-room
   "What are you afraid of, or what is chasing you?~%"
   (morse-code-cipher ceasar-cipher)
   ("bear")
   "A muffled scream startles you. As you turn, you notice something stuck in a crevice under the table.  A key falls to the floor."
   (heavy-key))
            ;; solved by first using a morse code translator and then using a ceasar cipher (shifted 1 over)
 )
)



(defparameter *location* 'lobby)

(defparameter *seen* '())     ;; Value of *seen* represents the current map file

(defparameter *upper-rooms-seen* '(1 2))   ;; a list to track rooms "seen" by player

(defparameter *basement-rooms-seen* '())

(defparameter *basement-rooms-all* '(passage stock-room cellar closet laboratory laundry control-room secret-room gypsy-room))

(defparameter *locked-rooms* '(gun-room laboratory closet secret-room))  ;; initialize locked doors

(defparameter *library-trap-sprung* nil)

(defparameter *laundry-trap-sprung* nil)

(defparameter *gypsy-trap-sprung* nil)

(defparameter *score* 0)      ;; Value of player's *score* is total of objects picked-up.


(defparameter *users-life* 100)   ;; these values affect outcome of battle
(defparameter *user-attack 0)
(defparameter *bears-life* 400)
(defparameter *bear-attack 0)



(defvar answer nil)        ;; defines the answer variable for user input

(defvar have-required-items nil)  ;; defines variable if a user has required items for puzzle




(defun describe-location (location map)
  "Player's current location in the house."
(second (assoc location map))
)

(defun describe-path (path)
  "Describes the provided path."
 `(there is a ,(second path) going ,(first path) from here.)
)

(defun describe-paths (location map)
  "Calls #'describe-path on every path leading away from the room the user is currently located in."
 (apply #'append (mapcar #'describe-path (cddr (assoc location map))))
)

(defun is-at (obj loc obj-loc)
  "Checks if an object is at a given location."
 (eq (second (assoc obj obj-loc)) loc)
)

(defun describe-floor (loc objs obj-loc)
  "Lists every item located at a given location."
 (apply #'append
  (mapcar
   (lambda (x) `(you see a ,x on the floor.))
   (remove-if-not (lambda (x) (is-at x loc obj-loc)) (mapcar 'first objs))
  )
 )
)


(defun update-rooms-seen ()   ;; pushes values onto list for rooms seen.
 (cond
    ;;--------upper-rooms---------------------------
   ((string-equal "hallway" (symbol-name *location*))
     (process-upper-rooms-seen 3)
     (process-upper-rooms-seen 4))
   ((string-equal "bathroom" (symbol-name *location*))
     (process-upper-rooms-seen 5))
   ((string-equal "stairway" (symbol-name *location*))
     (process-upper-rooms-seen 5)
     (process-upper-rooms-seen 6))
   ((string-equal "dining-room" (symbol-name *location*))
     (process-upper-rooms-seen 7))
   ((string-equal "gun-room" (symbol-name *location*))
     (process-upper-rooms-seen 8))
    ;;--------basement-rooms-------------------------
   ((string-equal "passage" (symbol-name *location*))
     (process-basement-rooms-seen 1)
     (process-basement-rooms-seen 2)
     (process-basement-rooms-seen 3))
   ((string-equal "laboratory" (symbol-name *location*))
     (process-basement-rooms-seen 4)
     (process-basement-rooms-seen 5))
   ((string-equal "laundry" (symbol-name *location*))
     (process-basement-rooms-seen 6))
   ((string-equal "closet" (symbol-name *location*))
     (process-basement-rooms-seen 7))
   ((string-equal "secret-room" (symbol-name *location*))
     (process-basement-rooms-seen 8)
     (process-basement-rooms-seen 9))
    ;;--------outside--------------------------------
   ;;((string-equal "outside" (symbol-name *location*))
     ;;(bear-fight))
 )
)

  
(defun process-upper-rooms-seen (number)       ;; called by update-rooms-seen
(cond
  ((not (member number *upper-rooms-seen*))
  (push number *upper-rooms-seen*)
  (setf *upper-rooms-seen* (sort *upper-rooms-seen* #'<))))
)

(defun process-basement-rooms-seen (number)    ;; called by update-rooms-seen
(cond
  ((not (member number *basement-rooms-seen*))
  (push number *basement-rooms-seen*)
  (setf *basement-rooms-seen* (sort *basement-rooms-seen* #'<))))
)


           ;; Called by print-map to ID rooms seen.
(defun get-room-sequence (var)
  "returns a concatenated string with all values in a list"
 (let ((z ""))                              ;; set appending string to hold appends
  (loop for x in (setf var (sort var #'>))  ;; loop through list for strings
     do
      (setf z (concatenate 'string (write-to-string x) z)))
  (setf var (sort var #'<))     ;; sort back to original state
  z                             ;; return "z" (the string of rooms seen)
 )
)

(defun check-for-trap ()    ;; upon entering a room, checks for and executes "trap"
 (cond
 ((and (not *library-trap-sprung*) (string-equal "library" (symbol-name *location*)))
  (print-warning '"images/dodge.txt")
  (princ "There is a pillar falling on you! Type DODGE within 5 seconds to survive!")
  (setf *library-trap-sprung* 1)
  (cond 
  ((not (alert-event 5 "dodge"))  ;; case insensitive
   (death))))
 ((and (not *laundry-trap-sprung*) (string-equal "laundry" (symbol-name *location*)))
  (print-warning '"images/jump.txt")
  (princ "The floor falls out from under you! Before it gives way, type JUMP within 3 seconds to survive!")
  (setf *laundry-trap-sprung* 1)
  (cond 
  ((not (alert-event 3 "jump"))   ;; case insensitive
   (death))))
 ((and (not *gypsy-trap-sprung*) (string-equal "gypsy-room" (symbol-name *location*)))
  (print-warning '"images/dive.txt")
  (princ "You are greeted by two barrels of a shot gun! DIVE out of the way or you are a goner! (2 seconds)")
  (setf *gypsy-trap-sprung* 1)
  (cond 
  ((not (alert-event 2 "dive"))   ;; case insensitive
   (death)))))
)


              ;; called by check-for-trap
(defun alert-event (time event-string)
    "Trigger event where the user must type in a string in a certain amount of time"
    ;; @author Kurt
   (format t "~%Enter a string: ")
   (let ((x (get-universal-time)) (user-input (read)) )
      (let ((y (get-universal-time)) )
           (let ((diff (- y x)))
                (cond
                   ((< time diff)
                       (format t " Too slow - you failed to evade the trap! ~%"))
                   ((not (string-equal event-string user-input))
                       (format t " Incorrect input - you failed to evade the trap! ~%"))
                   (t (format t " Whew, that was close!!! ~%~%") 1 )  ;; returning any non-nil value as true
                )
            )
       )
   )
)


(defun check-outside ()
  "The following function prompts the user if they wish to play again. If yes, then play-game will be called."
  (cond 
   ((string-equal "outside" (symbol-name *location*))
    (format t "You are about to go outside to face the bear. Are you sure you want to do this? [y/n]~%")
    (let ((x (read)))
      (cond 
       ((string-equal x "y")
        (bear-fight))
       ((string-equal x "n")
        (setf *location* 'lobby))
       (t
        (format t "You must enter [y/n] ~%")
        (check-outside)))))
  )
)

          ;;; Generates a random number [low, high]
(defun select-number (high low)
  "The following function generates a random number [low,high]"
  (floor (+ (* (random 1.0) (- high low)) low))
)

(defun bear-fight ()
  "Calculates your item-attack-score on the fly and initiates the fight sequence"
  (loop for x in (inventory)
        do (setf *score* (+ (third (assoc x *objects*)) *score*)))
  (format t "You have chosen a showdown with the bear! The bear eyes you with ravenous hunger.~%")
  (format t "Derrived all the items you have collected, your final attack score is: ~a~%" *score*)
  (format t "Your attack score will modify the damage you do to the bear.~%~%")
  (conduct-fight)
)

(defun conduct-fight ()
  "Starts the fight simulation between the user and the bear"
  (format t "You have: ~D life ~% The bear has: ~D life~%~% The fight begins...~%" *users-life* *bears-life*) 
  (loop while (and (> *users-life* 0) (> *bears-life* 0)) do
        (let ((x (select-number 21 1))(z (select-number 25 10)))
          ;(print x)
          (format t "You attack bear for: [~D] + ~D. " x *score*)
          (setf *bears-life* (- *bears-life* (+ *score* x)))
          (format t "Bear has ~D life left.~%" *bears-life*)
          (cond
           ((> *bears-life* 0)
            (format t "Bear attacks you for: [~D] " z)
            (setf *users-life* (- *users-life* z))
            (format t "You have ~D life left.~%" *users-life*)))))
  (cond
   ((<= *users-life* 0)
    (format t "The bear pwnt you and is now eating your mutilated corpse!~%")
    (death))
   ((<= *bears-life* 0)
    (format t "Bear dies.~%The bear is dead. Well done Chuck Norris!~% Would you like to play again? [y/n]")
    (ask-to-play-again)))
)

(defun ask-to-play-again ()
	  "The following function prompts the user if they wish to play again. If yes, then play-game will be called."
	 (let ((x (read)))
	    (cond 
	     ((string-equal x "y")
	      (format t "Reloading game. Type (look) to see your surroundings~%")
	      (load (concatenate 'string *path-to-game* "game.lisp")))
	     ((string-equal x "n")
	      (format t "Goodbye ~%") 1)
	     (t
	      (format t "You must enter [y/n] ~%")
	      (ask-to-play-again))))
)

(defun death ()
  "User died function."
 (format t "Sorry noob, you died.. ~%")
 (format t "Would you like to play again? [y/n]~%")
 (ask-to-play-again)
)

(defun lock (room)
"Adds room to *locked-rooms*"
(setf *locked-rooms* (push room *locked-rooms*))
)

(defun unlock (room)
"Removes room from *locked-rooms*"
(setf *locked-rooms* (remove room *locked-rooms*))
)

 ;; SPEL macros
(defmacro defspel (&rest rest) `(defmacro ,@rest))


(defspel walk (direction)
`(walk-direction ',direction)
)

(defun walk-direction (direction)
  "Changes the user's current location."
 (let ((next (assoc direction (cddr (assoc *location* *map*)))))
  (cond
    ;; If the next room is locked, exit function and report to the user that they cannot enter the room.
   ((member (third next) *locked-rooms*) (return-from walk-direction '(that room is locked.)))
  )
  (cond
    ;; If the direction is defined for the current room, change the user's location and call #'look.
   (next (setf *location* (third next)) 
         (cond
          ((not (check-for-trap)) (update-rooms-seen) (check-outside) (look))))
    ;; Else, report to the user that they cannot move that direction.
   (t '(you cant go that way.))
  )
 )
)

(defun print-warning (action-name)
  "Function to print big ascii warning texts to the user"
  (let ((in (open (concatenate 'string *path-to-game* action-name))))  ;; handles no-file error 
  (when in
   (loop for line = (read-line in nil)       ;; EOF returns nil
    while line do (format t "~a~%" line)
   )
   (close in)
  )
 )
)


(defun look ()
  "Calls all the descriptive functions."
 (cond
  ((not (string-equal "outside" (symbol-name *location*)))
       (append
        (describe-location *location* *map*)
        (describe-paths *location* *map*)
        (describe-floor *location* *objects* *object-locations*)
        (print-map)))
  (t (print-map))))

(defun print-map () 
  "Prints the current map from a file."
 (cond
  ((string-equal "outside" (symbol-name *location*))
   (setf *seen* (concatenate 'string *path-to-game* "images/bear.txt")))
  ((not (member *location* *basement-rooms-all*))   ;; is current location in basement???
   (cond 
    ((string-equal "12" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_01.txt")))
    ((string-equal "1234" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_02.txt")))
    ((string-equal "12345" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_03.txt")))
    ((string-equal "123456" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_04.txt")))
    ((string-equal "1234567" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_05.txt")))
    ((string-equal "1234568" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_06.txt")))
    ((string-equal "12345678" (get-room-sequence *upper-rooms-seen*))
     (setf *seen* (concatenate 'string *path-to-game* "maps/G_07.txt")))
   )
  )
  ((string-equal "123" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_01.txt")))
  ((string-equal "12345" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_03.txt")))
  ((string-equal "123456" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_04.txt")))
  ((string-equal "123457" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_11.txt")))
  ((string-equal "1237" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_05.txt")))
  ((string-equal "123789" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_07.txt")))
  ((string-equal "1234567" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_08.txt")))
  ((string-equal "12345789" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_09.txt")))
  ((string-equal "123456789" (get-room-sequence *basement-rooms-seen*))
   (setf *seen* (concatenate 'string *path-to-game* "maps/B_10.txt")))
 )
 (let ((in (open *seen* :if-does-not-exist nil)))  ;; handles no-file error 
  (when in
   (loop for line = (read-line in nil)       ;; EOF returns nil
    while line do (format t "~a~%" line)
   )
   (close in)
  )
 )
 (cond
  ((not (string-equal "outside" (symbol-name *location*)))
   (format t "You are located in: ~a~%" *location*)))
)                       ;; end of print-maps


(defspel pickup (object)
`(pickup-object ',object)
)

(defun pickup-object (object)
"Allows the user to add an item to their inventory."
(cond
  ;; If the user is at the same location as the object and adds it to the user's inventory.
 ((is-at object *location* *object-locations*) (push (list object 'body) *object-locations*) `(you are now carrying the ,object))
  ;; Else, report to the user that they cannot pick up the item.
 (t '(you cannot get that.))
)
)

(defun have (object)
 "Checks if the object is in the user's inventory."
(member object (inventory))
)

(defun inventory ()
 "Displays the user's inventory."
  (remove-if-not (lambda (x) (is-at x 'body *object-locations*)) (mapcar 'first *objects*))
)

(defspel examine (item)
  "Provides possesed item's description"
  (cond
    ;; Checks to see if the user has the item.
    ((have item)(second (assoc item *objects*)))
    (t "You must pickup the item first!")
  )
)

;;------------- Puzzle Related Methods --------------

 ;; Solve function:
 ;;  Obtains location of player, matches location to a puzzle location
 ;;  Prints puzzle, reads user input, checks input against answer
 ;;  If correct, print victory message, push item to item list and
 ;;  push item to current objects in object location
 ;;  If false, display error prompt
(defun solve() ;; empty parameter list
  "Allows the user to solve a puzzle in the player's current room."
  (let ((puzzle-name (second (assoc *location* *puzzle-locations*))))
  (cond
    ((and puzzle-name)
      (progn
        (loop for y in (third (assoc puzzle-name *puzzles*)) ;; iterates all required items for a given puzzle
          do (cond
               ((not (have y)) (return-from solve '(You are baffled by the complexity of the puzzle.  You feel as though you are missing something.))) ;; if items are missing, prints message
             )
        )
        (show-question puzzle-name) ;; compares current location to each puzzle location in puzzle list and checks required items
        (setf answer (read-line))  ;; reads user input and sets to the answer variable
        (compare-answer answer puzzle-name *puzzles*)  ;; compares user answer to actual answer
      )
    )
    (t (princ "There is no puzzle here to solve."))  ;; prints message if there is no puzzle at current locaiton
  )
  )
)


;; method to print the puzzle question
(defun show-question (puzzle-name)
  (format t (second (assoc puzzle-name *puzzles*)))
)

;; method to compare a user answer (given in parameter)
;; to puzzle answer. If correct, method calls puzzle-solved method
(defun compare-answer(answer puzzle-name puzzle-list)
 (cond
  ((equal `(,answer) (fourth (assoc puzzle-name puzzle-list))) ;; compares user answer to puzzle answer
   (puzzle-solved puzzle-name puzzle-list)) ;; if correct, calls puzzle-solved
  (t (princ "Sorry, that is incorrect.")) ;; prints message if user answer is incorrect
 )
)

;; method to print the reward statment for correctly solving puzzle
;; pushes the reward item to the object list
;; pushes the reward item to the current location for user to pick up
(defun puzzle-solved (puzzle-name puzzle-list)
  (format t (fifth (assoc puzzle-name puzzle-list)))  ;; Informs player of new object
  (loop for x in (sixth (assoc puzzle-name puzzle-list))
    do (push (list x *location*) *object-locations*)
  )
)

(defmacro use (key)
    "Opens the corresponding room given the correct key"
  (unlock (second (assoc key *key-rooms*)))
  (return-from use "You turn the key slowly and hear the lock pop!")
)
